Skip to content

dgb: v36 donation version-gate (pillar 4 of modern-layer activation) - #82

Merged
frstrtr merged 1 commit into
masterfrom
dgb/activate-v36-modern-layer
Jun 11, 2026
Merged

dgb: v36 donation version-gate (pillar 4 of modern-layer activation)#82
frstrtr merged 1 commit into
masterfrom
dgb/activate-v36-modern-layer

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Scope: pillar 4 (donation migration) only — pillar 1 has no activation surface yet

This PR lands the one part of the v36 modern-layer activation that has a real,
isolated surface in src/impl/dgb/ today: the version-gated donation script.

What changed (src/impl/dgb/config_pool.hpp, additive, header-only)

  • Add the pre-V36 DONATION_SCRIPT (105-byte OP_2 / 3x33B pubkey / OP_3
    OP_CHECKMULTISIG bare multisig). Bytes are the DGB v35 canonical donation
    from farsider350 p2pool-dgb-scrypt-350 p2pool/data.py:66 — generated
    programmatically from the verified hex, not hand-transcribed.
  • Gate get_donation_script(version): >=36 -> shared COMBINED P2SH 1-of-2
    (byte-identical to LTC); <36 -> the farsider350 2-of-3.

Previously get_donation_script() ignored the version and always returned
COMBINED — DGB was missing its pre-V36 donation entirely. The DGB v35 form is
the 2-of-3 multisig, not the LTC/BTC P2PK form, so this migration is
DGB-specific. Constants confirmed against the directive + operator-confirmed scope.

Why pillar 1 (version-voting / AutoRatchet) is NOT in this PR

Mirroring BTC #81 presumes a modern sharechain stack that DGB does not have yet:

  • no src/c2pool/main_dgb.cpp (only c2pool-btc is an executable target)
  • no src/impl/dgb/auto_ratchet.hpp
  • no src/impl/dgb/share_check.hpp / share_tracker.hpp
  • no src/impl/dgb/stratum/work_source.{hpp,cpp}

There are zero hardcoded share_version=35 sites to replace because DGB has
no share-creation/gentx path. Pillar 1 activation first requires porting the LTC
modern layer (~6.8K LOC) into src/impl/dgb/ + creating main_dgb.cpp + a
c2pool-dgb executable target. That is multi-day work (overlaps M3 Phase C),
surfaced to integrator as a discovery/scope decision — not foldable into a
short-turn activation PR.

Pillars 2/3

Both absent (not present-inert): no DensePPLNSRing, no anti-hop — the
share_tracker/PPLNS layer is unported.

Boundary / safety

  • src/impl/dgb/ only. Did NOT touch share_check.hpp F10, ltc/, or core.
  • GPG-signed, no third-party attribution. Build-inert (skeleton dormant; nothing
    calls get_donation_script until the gentx path lands).
  • Preflight waiver: c2pool-preflight.sh exits RED on pre-existing
    src/impl/doge/coin/* -> impl/ltc/coin/* cross-coin includes (shared DOGE-aux
    module, not my domain) + a core sharechain.hpp iterator WARN. None touch this
    diff, which only adds two constexpr std::array members to a dgb header.

Add the pre-V36 DGB donation script and gate get_donation_script() on
share version, completing the v36 donation migration for c2pool-dgb:

  pre-V36 : farsider350 2-of-3 bare multisig (DGB v35 canonical donation,
            from p2pool-dgb-scrypt-350 p2pool/data.py:66 DONATION_SCRIPT)
  V36+    : shared COMBINED P2SH 1-of-2 (byte-identical to LTC network)

Previously get_donation_script() ignored the version and always returned
COMBINED; DGB was missing its pre-V36 donation entirely. The v35 bytes are
the farsider350 2-of-3 OP_CHECKMULTISIG script (NOT the LTC P2PK form), so
the migration is DGB-specific. Matches the donation transition in
p2pool-merged-v36. Header-only and additive; no behavioral change until the
modern share-creation/gentx path is wired into a c2pool-dgb binary.
@frstrtr
frstrtr merged commit 6033acd into master Jun 11, 2026
16 checks passed
frstrtr added a commit that referenced this pull request Jun 14, 2026
Phase A (#82) leaf deps for the embedded P2P+mempool layer. 1:1 mirror of
src/impl/btc/coin (DGB is structurally BTC-shaped, non-MWEB; Scrypt PoW
divergence lives in header_chain.hpp). block.hpp carries the multi-algo note:
the version field encodes the mining algo but the 80-byte header layout is
single-format and algo-agnostic; algo selection is read in header_chain, not
in (de)serialization. node_interface.hpp restores the members the Path-A stub
deferred (new_tx/new_headers/full_block/txidcache/known_txs), now that the
types exist.
frstrtr added a commit that referenced this pull request Jun 14, 2026
Phase A (#82). 1:1 mirror of src/impl/btc/coin (non-MWEB). SegWit/wtxid
short-IDs apply (DGB activated SegWit). No coin-specific magic/consensus
constants in this layer.
frstrtr added a commit that referenced this pull request Jun 14, 2026
Phase A (#82). 1:1 mirror of src/impl/btc/coin (non-MWEB) speaking the
DigiByte Core wire protocol; Scrypt-only. Two P2P-handshake constants carried
from BTC are flagged TODO(M3) for reconciliation vs DigiByte Core params:
protocol_version (70016) and advertised port (8333 -> DGB mainnet 12024).
Neither is consensus. dgb_coin CMake lists the new files but stays
unreferenced by add_subdirectory() pending the ci-steward OBJECT-lib wiring.
frstrtr added a commit that referenced this pull request Jun 14, 2026
Flip per OBJECT-lib convention: register src/impl/dgb at top level and enable the coin subdir under COIN_DGB. dgb_coin now builds standalone (-DCOIN_DGB=ON); libdgb_coin.a links clean, 0 errors. daemon/test stay commented (M3).
frstrtr added a commit that referenced this pull request Jun 14, 2026
DGB Phase A: embedded P2P + mempool (#82)
frstrtr added a commit that referenced this pull request Jun 18, 2026
Add two KATs to block_assembly_test proving the won-block witness shape is
governed by whether the gentx carries a witness (i.e. is_segwit_activated at
gentx-build time), not by an unconditional witness branch in the framer:

  * SegwitGentxEmitsWitnessBlock: a gentx carrying the BIP141 coinbase witness
    reserved value => TX_WITH_WITNESS block (strictly larger than legacy, marker
    emitted, reserved value round-trips). DGB SEGWIT_ACTIVATION_VERSION=35.
  * LegacyGentxEmitsLegacyBlock: a no-witness gentx => legacy block, no
    marker/flag, byte-stable re-serialization (the BCH is_segwit_activated()==0
    shape the companion bch test asserts).

block_assembly.hpp: correct the wire-encoding comment from unconditional
(TX_WITH_WITNESS) to the conditional TX_WITH_WITNESS(m_txs) Bitcoin-Core codec.

src/impl/dgb/ only; no p2pool-merged-v36 surface; same dgb_block_assembly_test
target already in test/CMakeLists.txt + both build.yml allowlists.
frstrtr added a commit that referenced this pull request Jun 18, 2026
Pin the embedded-primary / external-digibyted-RPC-fallback contract of
dgb::coin::CoinNode (core::coin::ICoinNode) that the won-block dispatch
relies on: web_server submits a solved block via
m_coin_node->submit_block_hex(), which forwards to NodeRPC::submitblock
(the external-daemon fallback that MUST persist alongside embedded).

Three invariants, mirroring impl/bch/test/coin_node_seam_test.cpp:
  1. no source        -> empty WorkView, no throw
  2. embedded, no rpc -> WorkView sourced from embedded
  3. no rpc sink      -> submit_block_hex == false (!m_rpc guard, no crash)

The live submitblock call + m_on_block_found tracker callback are wired
by the DGB run-loop standup (main_dgb.cpp is selftest-only today); that
is the remaining #82 slice and is out of scope here (rpc=nullptr).

Registered in test/CMakeLists.txt AND both build.yml --target allowlists
(avoids the #143 NOT_BUILT-sentinel trap). 3/3 PASS, build EXIT=0.
frstrtr added a commit that referenced this pull request Jun 18, 2026
Add coin/block_broadcast.hpp -- broadcast_won_block(), the DGB dual-path
won-block dispatcher the run-loop wires tracker().m_on_block_found to. Fires
BOTH sinks per the broadcaster-gate rule: embedded P2P relay (PRIMARY, supplied
as a sink fn until NodeP2P/EmbeddedDaemon lands) AND external digibyted
submitblock via the CoinNode seam (FALLBACK, fired ALWAYS, ignore_failure=true
so a duplicate after a P2P accept never masks the win). landed_first records the
race winner; with neither sink live the call is a safe no-op (any()=false, no
throw, null seam never dereferenced). 1:1 contract mirror of bch
broadcast_won_block (90a3553); decoupled via std::function P2P sink + ICoinNode*
so it is build-verified now. DGB-Scrypt standalone parent -- no merged-coinbase
leg in the default build. Complements the #163 RPC-fallback seam half.

dgb_block_broadcast_test: 5-case dispatch contract (no-sink no-op, p2p-only,
rpc-only, dual-path always-fires-fallback, fallback-no-ack-does-not-mask-p2p)
over a fake ICoinNode -- 5/5 PASS, build EXIT=0. Registered in test/CMakeLists.txt
AND both build.yml --target allowlists (#143 NOT_BUILT trap avoided).

p2pool-merged-v36 surface: NONE (block dispatch only). Per-coin isolation:
src/impl/dgb/coin/ only.
frstrtr added a commit that referenced this pull request Jun 18, 2026
make_on_block_found turns a winning share hash into a broadcast: reconstruct
share->block via an injected WonBlockReconstructor, then fire broadcast_won_block
down both paths (P2P primary + external digibyted submitblock fallback). The
reconstructor is injected so the run-loop dispatch contract is build-verified and
run-tested now, before the faithful as_block reassembly is ported.

won_block_dispatch_test drives the handler end-to-end: known share fires both
paths, unknown/unassemblable share broadcasts nothing, RPC-only still reaches the
network, missing reconstructor is a safe no-op. 4/4 PASS. Registered in
test/CMakeLists.txt and both build.yml --target allowlists (avoids the #143
NOT_BUILT trap). src/impl/dgb/ only; no p2pool-merged-v36 surface.
frstrtr added a commit that referenced this pull request Jun 18, 2026
…5 KATs (#168)

* dgb(#82): faithful as_block FRAMING half — share->block reassembly

Port the FRAMING half of p2pool data.py Share.as_block into
src/impl/dgb/coin/block_assembly.hpp: reconstruct the full block header
merkle_root from the gentx hash walked up the share merkle_link (the
SmallBlockHeader stored on a share omits merkle_root), then frame the
block txs as [gentx] ++ other_txs (coinbase at index 0) and serialize
through the live BlockType codec NodeRPC::submit_block already uses, so
the reconstructed block round-trips and a daemon accepts it byte-for-byte.

gentx bytes + known_txs lookup stay INJECTED (the gentx-byte build that
hits coinbase-byte adjudication is the next reconstructor slice); this
pins the framing + merkle_root math now. dgb_block_assembly_test: 5 KATs
(empty-branch root==gentx_hash, index-bit side select, coinbase-first
round-trip, coinbase-only) registered in BOTH test/CMakeLists.txt and the
build.yml --target allowlist. Per-coin isolation: src/impl/dgb/ only;
p2pool-merged-v36 surface: none.

* dgb(#82): assert won-block witness predicate (is_segwit_activated gate)

Add two KATs to block_assembly_test proving the won-block witness shape is
governed by whether the gentx carries a witness (i.e. is_segwit_activated at
gentx-build time), not by an unconditional witness branch in the framer:

  * SegwitGentxEmitsWitnessBlock: a gentx carrying the BIP141 coinbase witness
    reserved value => TX_WITH_WITNESS block (strictly larger than legacy, marker
    emitted, reserved value round-trips). DGB SEGWIT_ACTIVATION_VERSION=35.
  * LegacyGentxEmitsLegacyBlock: a no-witness gentx => legacy block, no
    marker/flag, byte-stable re-serialization (the BCH is_segwit_activated()==0
    shape the companion bch test asserts).

block_assembly.hpp: correct the wire-encoding comment from unconditional
(TX_WITH_WITNESS) to the conditional TX_WITH_WITNESS(m_txs) Bitcoin-Core codec.

src/impl/dgb/ only; no p2pool-merged-v36 surface; same dgb_block_assembly_test
target already in test/CMakeLists.txt + both build.yml allowlists.

---------

Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
frstrtr added a commit that referenced this pull request Jun 18, 2026
…-trip KAT

Factor the p2pool non-witness coinbase (gentx) wire layout out of
generate_share_transaction() (share_check.hpp:933, the verification SSOT)
into coin/gentx_coinbase.hpp::assemble_gentx_coinbase() so emission and
verification cannot diverge on a byte. Pure: takes already-built
scripts/amounts (no tracker/share-template dependency) so it is directly
KAT-able; this is the single builder that create_local_share() and the
won-block reconstruction body will consume in follow-up slices.

KAT vectors are GROUND-TRUTH from the canonical oracle
frstrtr/p2pool-dgb-scrypt (util/pack.py byte logic + bitcoin/data.py
tx_id_type; donation script 4104ffd0...ac), not self-generated, so a PASS
proves build -> non-witness serialize -> double-SHA256 == oracle bytes/txid,
not mere self-consistency. Covers the no-segwit and witness-commitment-first
layouts; the only DGB<->BCH divergence is the gated segwit predicate at
serialize time. dgb_gentx_coinbase_test 3/3 PASS, build EXIT=0; target wired
into ctest + BOTH build.yml --target allowlists (#143 NOT_BUILT trap avoided).

Scope: factor + KAT only. The won-block-reaches-network wiring (m_on_block_found
and submit_block_hex) is fix #82 and stays separate.
frstrtr added a commit that referenced this pull request Jun 18, 2026
…-trip KAT (#171)

Factor the p2pool non-witness coinbase (gentx) wire layout out of
generate_share_transaction() (share_check.hpp:933, the verification SSOT)
into coin/gentx_coinbase.hpp::assemble_gentx_coinbase() so emission and
verification cannot diverge on a byte. Pure: takes already-built
scripts/amounts (no tracker/share-template dependency) so it is directly
KAT-able; this is the single builder that create_local_share() and the
won-block reconstruction body will consume in follow-up slices.

KAT vectors are GROUND-TRUTH from the canonical oracle
frstrtr/p2pool-dgb-scrypt (util/pack.py byte logic + bitcoin/data.py
tx_id_type; donation script 4104ffd0...ac), not self-generated, so a PASS
proves build -> non-witness serialize -> double-SHA256 == oracle bytes/txid,
not mere self-consistency. Covers the no-segwit and witness-commitment-first
layouts; the only DGB<->BCH divergence is the gated segwit predicate at
serialize time. dgb_gentx_coinbase_test 3/3 PASS, build EXIT=0; target wired
into ctest + BOTH build.yml --target allowlists (#143 NOT_BUILT trap avoided).

Scope: factor + KAT only. The won-block-reaches-network wiring (m_on_block_found
and submit_block_hex) is fix #82 and stays separate.

Co-authored-by: frstrtr <frstrtr@users.noreply.github.com>
frstrtr added a commit that referenced this pull request Jun 18, 2026
…b-slice 2)

Won-block reconstructor connecting tissue (sub-slice 2): coin/other_tx_assembler.hpp
bridges the ordered other_tx hash list from resolve_other_tx_hashes (sub-slice 1)
to the deserialized MutableTransaction vector that assemble_won_block frames as
txs = [gentx] ++ other_txs. Faithful port of the known_txs lookup in p2pool
data.py Share.as_block: other_txs = [known_txs[h] for h in transaction_hashes].

The known-tx lookup is INJECTED as a (hash) -> const MutableTransaction* callable
(nullptr == unknown), mirroring the seam-first decomposition of sub-slice 1 and
won_block_dispatch.hpp, so the bridge is unit-testable against a synthetic
known-tx set without a live mempool. A missing hash THROWS std::out_of_range
rather than dropping/placeholder-filling the tx: a block with a missing other_tx
has the wrong merkle root and is daemon-rejected, so loud failure is strictly
safer than emitting a malformed block.

Witness framing is not decided here -- the txs are returned verbatim and the
block witness shape stays governed by assemble_won_block`s TX_WITH_WITNESS
conditional codec. DGB is segwit-active (SEGWIT_ACTIVATION_VERSION, v36 >= it),
so the path is live; the KAT pins that a witness-bearing other_tx flips the
assembled block to the witness codec via the other_tx leg, not gentx-only.

dgb_other_tx_assembler_test: 5/5 PASS -- order-preserve, missing-throws, empty,
end-to-end resolve->assemble->frame (coinbase-first, ref order), witness
reachability. Wired into test/CMakeLists.txt + both build.yml --target
allowlists (#143 NOT_BUILT trap). Per-coin isolation: src/impl/dgb/ only;
p2pool-merged-v36 surface: NONE.
frstrtr added a commit that referenced this pull request Jun 19, 2026
…coinbase

generate_share_transaction (verification path) and create_local_share
(emission path) each open-coded the coinbase wire layout
(version|vin|vouts|locktime) and the txid double-SHA256. Two byte paths
pinned to the same oracle vector = proven-equivalent, not unified: a
third edit could still diverge them.

Collapse both onto dgb::coin::assemble_gentx_coinbase() (coin/gentx_coinbase.hpp,
the #171 SSOT) so emission == verification == one source. Each call site
now only builds its per-share inputs (coinbase script, optional segwit
witness-commitment script, PPLNS payout outputs, donation, OP_RETURN ref
commitment) and hands them to the assembler; the assembler owns wire
framing + txid. PackStream tx is reconstructed from the SSOT bytes so the
downstream V36 hash_link diagnostics are byte-for-byte unchanged.

No oracle vector regeneration. Single-coin scope: src/impl/dgb/ only.
dgb build EXIT=0; dgb_share_test 5/5; dgb_gentx_coinbase_test 3/3.
frstrtr added a commit that referenced this pull request Jun 19, 2026
generate_share_transaction computes the coinbase via assemble_gentx_coinbase
(the SSOT proven by #172) but returned only the gentx_hash, discarding the
bytes. reconstruct_won_block needs the exact non-witness coinbase bytes -- it
is block tx[0] and its txid is the merkle leaf -- not just the hash.

Add an optional out_gentx (GentxCoinbase*) param, default nullptr: zero change
for the verification callers, surfaces {bytes,txid} for the reconstructor. KAT
proves the exposed bytes hash to the returned gentx_hash and deserialize into
the coinbase MutableTransaction that assemble_won_block frames, round-tripping
byte-identically (non-witness). Single-coin (src/impl/dgb/ only); reuses the
existing #172 dgb_gentx_share_path_test target (no new allowlist entry).
frstrtr added a commit that referenced this pull request Jun 19, 2026
…coinbase

generate_share_transaction (verification path) and create_local_share
(emission path) each open-coded the coinbase wire layout
(version|vin|vouts|locktime) and the txid double-SHA256. Two byte paths
pinned to the same oracle vector = proven-equivalent, not unified: a
third edit could still diverge them.

Collapse both onto dgb::coin::assemble_gentx_coinbase() (coin/gentx_coinbase.hpp,
the #171 SSOT) so emission == verification == one source. Each call site
now only builds its per-share inputs (coinbase script, optional segwit
witness-commitment script, PPLNS payout outputs, donation, OP_RETURN ref
commitment) and hands them to the assembler; the assembler owns wire
framing + txid. PackStream tx is reconstructed from the SSOT bytes so the
downstream V36 hash_link diagnostics are byte-for-byte unchanged.

No oracle vector regeneration. Single-coin scope: src/impl/dgb/ only.
dgb build EXIT=0; dgb_share_test 5/5; dgb_gentx_coinbase_test 3/3.
frstrtr added a commit that referenced this pull request Jun 19, 2026
generate_share_transaction computes the coinbase via assemble_gentx_coinbase
(the SSOT proven by #172) but returned only the gentx_hash, discarding the
bytes. reconstruct_won_block needs the exact non-witness coinbase bytes -- it
is block tx[0] and its txid is the merkle leaf -- not just the hash.

Add an optional out_gentx (GentxCoinbase*) param, default nullptr: zero change
for the verification callers, surfaces {bytes,txid} for the reconstructor. KAT
proves the exposed bytes hash to the returned gentx_hash and deserialize into
the coinbase MutableTransaction that assemble_won_block frames, round-tripping
byte-identically (non-witness). Single-coin (src/impl/dgb/ only); reuses the
existing #172 dgb_gentx_share_path_test target (no new allowlist entry).
frstrtr added a commit that referenced this pull request Jun 19, 2026
dgb: #82 arm2 — bind sharechain m_on_block_found to won-block dispatcher
frstrtr added a commit that referenced this pull request Jun 20, 2026
dgb(#82): wire won-block P2P-relay PRIMARY arm to live coin-daemon producer
frstrtr added a commit that referenced this pull request Jun 20, 2026
dgb(#82): faithful won-block reconstruct closure + fail-closed KAT
frstrtr added a commit that referenced this pull request Jun 20, 2026
dgb(#82): bind 5 won-block reconstruct seams to live tracker (decision (a), deadlock-safe)
This was referenced Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant